package com.ruoyix.im.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
import com.ruoyix.common.core.domain.PageQuery;
import com.ruoyix.common.core.domain.R;
import com.ruoyix.common.core.domain.model.LoginUser;
import com.ruoyix.common.core.page.TableDataInfo;
import com.ruoyix.common.helper.LoginHelper;
import com.ruoyix.common.utils.DateUtils;
import com.ruoyix.common.utils.StringUtils;

import com.ruoyix.im.domain.ImChatGroup;
import com.ruoyix.im.domain.ImChatGroupUser;
import com.ruoyix.im.domain.ImChatUserGroupMessage;
import com.ruoyix.im.domain.bo.ImChatGroupBo;
import com.ruoyix.im.domain.vo.ImChatGroupVo;
import com.ruoyix.im.mapper.ImChatGroupMapper;
import com.ruoyix.im.mapper.ImChatGroupUserMapper;
import com.ruoyix.im.mapper.ImChatUserGroupMessageMapper;
import com.ruoyix.im.service.IImChatGroupService;
import com.ruoyix.im.service.IImChatUserGroupMessageService;
import com.ruoyix.im.websocket.ImConfigConst;
import com.ruoyix.im.websocket.TioWebsocketStarter;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.tio.core.Tio;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 聊天群Service业务层处理
 *
 * @author ruoyi
 * @date 2024-05-27
 */
@RequiredArgsConstructor
@Service
public class ImChatGroupServiceImpl extends ServiceImpl<ImChatGroupMapper, ImChatGroup> implements IImChatGroupService {

    private final ImChatGroupMapper baseMapper;
    private final ImChatGroupUserMapper imChatGroupUserMapper;
    private final TioWebsocketStarter tioWebsocketStarter;
    private final ImChatUserGroupMessageMapper imChatUserGroupMessageMapper;

    /**
     * 查询聊天群
     */
    @Override
    public ImChatGroupVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询聊天群列表
     */
    @Override
    public TableDataInfo<ImChatGroupVo> queryPageList(ImChatGroupBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<ImChatGroup> lqw = buildQueryWrapper(bo);
        Page<ImChatGroupVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询聊天群列表
     */
    @Override
    public List<ImChatGroupVo> queryList(ImChatGroupBo bo) {
        LambdaQueryWrapper<ImChatGroup> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<ImChatGroup> buildQueryWrapper(ImChatGroupBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<ImChatGroup> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getId() != null, ImChatGroup::getId, bo.getId());
        lqw.like(StringUtils.isNotBlank(bo.getGroupName()), ImChatGroup::getGroupName, bo.getGroupName());
        lqw.eq(bo.getMasterUserId() != null, ImChatGroup::getMasterUserId, bo.getMasterUserId());
        lqw.eq(StringUtils.isNotBlank(bo.getAvatar()), ImChatGroup::getAvatar, bo.getAvatar());
        lqw.eq(StringUtils.isNotBlank(bo.getIntroduction()), ImChatGroup::getIntroduction, bo.getIntroduction());
        lqw.eq(StringUtils.isNotBlank(bo.getNotice()), ImChatGroup::getNotice, bo.getNotice());
        lqw.eq(bo.getInType() != null, ImChatGroup::getInType, bo.getInType());
        lqw.eq(bo.getGroupType() != null, ImChatGroup::getGroupType, bo.getGroupType());
        return lqw;
    }

    /**
     * 新增聊天群
     */
    @Override
    public Boolean insertByBo(ImChatGroupBo bo) {
        ImChatGroup add = BeanUtil.toBean(bo, ImChatGroup.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改聊天群
     */
    @Override
    public Boolean updateByBo(ImChatGroupBo bo) {
        ImChatGroup update = BeanUtil.toBean(bo, ImChatGroup.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(ImChatGroup entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除聊天群
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public void createGroupCommon(ImChatGroup imChatGroup) {
        imChatGroup.setGroupType( ImConfigConst.GROUP_COMMON);
        Long userId = LoginHelper.getUserId();
        imChatGroup.setMasterUserId(userId);

        baseMapper.insert(imChatGroup);

        ImChatGroupUser imChatGroupUser = new ImChatGroupUser();
        imChatGroupUser.setGroupId(imChatGroup.getId());
        imChatGroupUser.setUserId(userId);
        imChatGroupUser.setAdminFlag(1);
        imChatGroupUser.setUserStatus( ImConfigConst.GROUP_USER_STATUS_PASS);

        imChatGroupUserMapper.insert(imChatGroupUser);
        Tio.bindGroup(tioWebsocketStarter.getServerTioConfig(), String.valueOf(userId), String.valueOf(imChatGroup.getId()));
    }

    @Override
    public void creatGroupTopic(ImChatGroup imChatGroup) {
        imChatGroup.setGroupType(ImConfigConst.GROUP_TOPIC);
        Long userId = LoginHelper.getUserId();
        imChatGroup.setMasterUserId(userId);
        imChatGroup.setInType(1);
        baseMapper.insert(imChatGroup);
    }

    public void updateGroup(ImChatGroup imChatGroup) {
        LambdaUpdateChainWrapper<ImChatGroup> lambdaUpdate = lambdaUpdate();
        lambdaUpdate.eq(ImChatGroup::getId, imChatGroup.getId());
        lambdaUpdate.eq(ImChatGroup::getMasterUserId, LoginHelper.getUserId());
        if (org.springframework.util.StringUtils.hasText(imChatGroup.getGroupName())) {
            lambdaUpdate.set(ImChatGroup::getGroupName, imChatGroup.getGroupName());
        }
        if (org.springframework.util.StringUtils.hasText(imChatGroup.getAvatar())) {
            lambdaUpdate.set(ImChatGroup::getAvatar, imChatGroup.getAvatar());
        }
        if (org.springframework.util.StringUtils.hasText(imChatGroup.getIntroduction())) {
            lambdaUpdate.set(ImChatGroup::getIntroduction, imChatGroup.getIntroduction());
        }
        // 群通知
        if (org.springframework.util.StringUtils.hasText(imChatGroup.getNotice())) {
            lambdaUpdate.set(ImChatGroup::getNotice, imChatGroup.getNotice());
        }
        // 修改进入方式
        if (imChatGroup.getInType() != null) {
            lambdaUpdate.set(ImChatGroup::getInType, imChatGroup.getInType());
        }
        // 转让群
        if (imChatGroup.getMasterUserId() != null) {
            lambdaUpdate.set(ImChatGroup::getMasterUserId, imChatGroup.getMasterUserId());
        }
        boolean isSuccess = lambdaUpdate.update();
        if (isSuccess && org.springframework.util.StringUtils.hasText(imChatGroup.getNotice())) {
            // todo 发送群公告
        }
    }


    public void deleteGroup(Long id) {
        LoginUser currentUser = LoginHelper.getLoginUser();
        boolean isSuccess;
        assert currentUser != null;
        if (currentUser.getUserType().equals("sys_admin")) {
            isSuccess = removeById(id);
        } else {
            LambdaUpdateChainWrapper<ImChatGroup> lambdaUpdate = lambdaUpdate();
            lambdaUpdate.eq(ImChatGroup::getId, id);
            lambdaUpdate.eq(ImChatGroup::getMasterUserId, LoginHelper.getUserId());
            isSuccess = lambdaUpdate.remove();
        }
        if (isSuccess) {
            // 删除用户
            LambdaUpdateChainWrapper<ImChatGroupUser> lambdaUpdate = ChainWrappers.lambdaUpdateChain(imChatGroupUserMapper);
            lambdaUpdate.eq(ImChatGroupUser::getGroupId, id).remove();
            // 删除聊天记录
            LambdaUpdateChainWrapper<ImChatUserGroupMessage> messageLambdaUpdateChainWrapper = ChainWrappers.lambdaUpdateChain(imChatUserGroupMessageMapper);
            messageLambdaUpdateChainWrapper.eq(ImChatUserGroupMessage::getGroupId, id).remove();
            Tio.removeGroup(tioWebsocketStarter.getServerTioConfig(), String.valueOf(id), "remove group");
        }
        R.ok();
    }

    public void addGroupTopic(Long id) {
        LambdaQueryChainWrapper<ImChatGroup> lambdaQuery = lambdaQuery();


        Long count = lambdaQuery.eq(ImChatGroup::getId, id)
            .eq(ImChatGroup::getGroupType,  ImConfigConst.GROUP_TOPIC).count();
        if (count == 1) {
            Tio.bindGroup(tioWebsocketStarter.getServerTioConfig(), String.valueOf(LoginHelper.getUserId()), String.valueOf(id));
        }
    }

    public List<ImChatGroupVo> listGroups() {
        Long userId = LoginHelper.getUserId();
        LambdaQueryChainWrapper<ImChatGroupUser> lambdaQuery = ChainWrappers.lambdaQueryChain(imChatGroupUserMapper, ImChatGroupUser.class);
        lambdaQuery.eq(ImChatGroupUser::getUserId, userId);
        lambdaQuery.in(ImChatGroupUser::getUserStatus, ImConfigConst.GROUP_USER_STATUS_PASS, ImConfigConst.GROUP_USER_STATUS_SILENCE);
        List<ImChatGroupUser> groupUsers = lambdaQuery.list();

        Map<Long, ImChatGroupUser> groupUserMap = groupUsers.stream().collect(Collectors.toMap(ImChatGroupUser::getGroupId, Function.identity()));
        LambdaQueryChainWrapper<ImChatGroup> wrapper = lambdaQuery();
        wrapper.eq(ImChatGroup::getGroupType, ImConfigConst.GROUP_TOPIC);
        if (!CollectionUtils.isEmpty(groupUserMap.keySet())) {
            wrapper.or(w -> w.in(ImChatGroup::getId, groupUserMap.keySet())
                .eq(ImChatGroup::getGroupType, ImConfigConst.GROUP_COMMON));
        }
        List<ImChatGroup> imChatGroups = wrapper.list();
        List<ImChatGroupVo> groupVOS = imChatGroups.stream().map(imChatGroup -> {
            ImChatGroupUser imChatGroupUser = groupUserMap.get(imChatGroup.getId());
            if (imChatGroupUser == null) {
                imChatGroupUser = new ImChatGroupUser();
                imChatGroupUser.setUserStatus(ImConfigConst.GROUP_USER_STATUS_PASS);
                imChatGroupUser.setCreateTime(DateUtils.getNowDate());
                imChatGroupUser.setUserId(userId);
                imChatGroupUser.setAdminFlag(LoginHelper.isAdmin()?1:0);
            }
            return getGroupVO(imChatGroup, imChatGroupUser);
        }).collect(Collectors.toList());
        return groupVOS;
    }

    private ImChatGroupVo getGroupVO(ImChatGroup imChatGroup, ImChatGroupUser imChatGroupUser) {
        ImChatGroupVo groupVO = new ImChatGroupVo();
        groupVO.setGroupName(imChatGroup.getGroupName());
        groupVO.setAvatar(imChatGroup.getAvatar());
        groupVO.setIntroduction(imChatGroup.getIntroduction());
        groupVO.setNotice(imChatGroup.getNotice());
        groupVO.setInType(imChatGroup.getInType());
        groupVO.setGroupType(imChatGroup.getGroupType());
        groupVO.setId(imChatGroup.getId());
        groupVO.setCreateTime(imChatGroupUser.getCreateTime());
        groupVO.setUserStatus(imChatGroupUser.getUserStatus());
        groupVO.setAdminFlag(imChatGroupUser.getAdminFlag());
        groupVO.setMasterFlag(imChatGroup.getMasterUserId().intValue() == imChatGroupUser.getUserId().intValue());
        return groupVO;
    }
}
